home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 295_01.zip / MANX.C < prev    next >
Text File  |  1993-04-22  |  11KB  |  400 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "manx.c    1.2 - 89/10/31" */
  5.  
  6. #if __STDC__ == 1
  7. #include <errno.h>
  8. #include <limits.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #define CONST const
  13. #else
  14. #include <errno.h>
  15. #include <limits.h>
  16. #include <stdio.h>
  17. void exit();            /* stdlib.h */
  18. #ifndef EXIT_SUCCESS
  19. #define EXIT_SUCCESS    (0)
  20. #define EXIT_FAILURE    (1)
  21. #endif
  22. long strtol();
  23. char *strstr();            /* string.h */
  24. int strncmp();
  25. int strcmp();
  26. int strlen();
  27. #define CONST
  28. #endif
  29.  
  30. #define PAGELEN        (60)        /* default page length */
  31. #define BACKSLASH    ('\\')        /* char to begin escape sequence */
  32. #define PAGINATOR    ("\f")        /* string to use as page separator */
  33. #define MAXLINE        (256)        /* maximum line length */
  34.  
  35. typedef struct {        /* language definition structure */
  36.     char option[11];    /* language command line option */
  37.     char begin[21];        /* marker for beginning of manual entry */
  38.     char end[21];        /* marker for end of manual entry */
  39.     char comment[11];    /* character sequence that begins comment */
  40.     int  flags;        /* flags */
  41. } lang_t;
  42.  
  43. /* lang_t bit flags */
  44. #define LINECMT        (1)
  45. #define BLOCKCMT    (2)
  46.  
  47. /* language definitions */
  48. lang_t langs[] = {
  49.     {"a",  "--man", "--end", "--", LINECMT},    /* Ada */
  50.     {"c",  "/*man", "*/",    "/*", BLOCKCMT},    /* C */
  51.     {"f",  "Cman", "Cend",   "C",  LINECMT},    /* Fortran */
  52.     {"l",  ";man", ";end",   ";",  LINECMT},    /* Lisp */
  53.     {"m",  "(*man", "*)",    "(*", BLOCKCMT},    /* Modula-2 */
  54.     {"p",  "{man",  "}",     "{",  BLOCKCMT},    /* Pascal */
  55.     {"pl", "\"man", "\"",    "\"", BLOCKCMT},    /* Prolog */
  56.     {"st", "\"man", "\"",    "\"", BLOCKCMT}    /* Smalltalk */
  57. };
  58.  
  59. /* index into langs array for each language */
  60. #define ADA        (1)
  61. #define C        (2)
  62. #define FORTRAN        (3)
  63. #define LISP        (4)
  64. #define MODULA_2    (5)
  65. #define PASCAL        (6)
  66. #define PROLOG        (7)
  67. #define SMALLTALK    (8)
  68.  
  69. #define LANG        C        /* default language */
  70.  
  71. /* command syntax */
  72. #define USAGE        ("Usage: manx [language] [page-length]")
  73.  
  74. #if __STDC__ == 1
  75. static int manputs(const char *cs, FILE *fp);
  76. #else
  77. static int manputs();
  78. #endif
  79.  
  80. /*man---------------------------------------------------------------------------
  81. NAME
  82.      manx - manual entry extracter
  83.  
  84. SYNOPSIS
  85.      manx [language] [page-length]
  86.  
  87. DESCRIPTION
  88.      The manx command extracts manual entries from source files.  The
  89.      source files are read from stdin and the manual entries are
  90.      written to stdout.  Each individual manual entry is separated
  91.      into pages by form feeds and terminated with a form feed.
  92.  
  93.      The language option specifies which language the source file is
  94.      written in.  The languages supported are:
  95.  
  96.                            Ada           -a
  97.                            C             -c
  98.                            Fortran       -f
  99.                            Lisp          -l
  100.                            Modula-2      -m
  101.                            Pascal        -p
  102.                            Prolog        -pl
  103.                            Smalltalk     -st
  104.  
  105.      The default language is C.
  106.  
  107.      The page-length argument can be used to set the page length.
  108.      Pagination may be disabled by specifying a page length of 0.
  109.      The default page length is 60.
  110.  
  111.      The beginning of a manual entry is marked by the character
  112.      sequence (language dependent) to start a comment immediately
  113.      followed by the characters 'man'.  This marker must appear in the
  114.      leftmost column allowed by the language.  For block comments, the
  115.      end of the manual entry is marked by the end of the comment.  For
  116.      line comments, the end of a manual entry is marked by the
  117.      character sequence to end a comment immediately followed by the
  118.      characters 'end'.  All lines between but not including these
  119.      constitute the manual entry.
  120.  
  121.      The following escape sequences can be used within a manual entry:
  122.  
  123.                   audible alert       BEL       \\a
  124.                   backspace           BS        \\b
  125.                   carriage return     CR        \\r
  126.                   horizontal tab      HT        \\t
  127.                   backslash           \\         \\\\
  128.  
  129. EXAMPLE
  130.      On a UNIX system, the following command would extract the manual
  131.      pages from all C files in the current UNIX directory, paginate
  132.      them every 52 lines, and place them in a file called manual.
  133.  
  134.           $ cat *.c | manx -c 52 > manual
  135.  
  136.      Catenating files is much for difficult in MS-DOS.  For this
  137.      system, the following sequence of commands is required.
  138.  
  139.           > copy file.c/a+file2.c+file3.c+file4.c tmp
  140.           > type tmp | manx -c 52 > manual
  141.           > del tmp
  142.  
  143.      manx works particularly well when used in conjunction with a make
  144.      utility.  Below are the relevant parts of the makefile for a C
  145.      library for which manx is used to extract the reference manual.
  146.  
  147.           LIB     = blkio
  148.           MAN     = $(LIB).man
  149.  
  150.           MANFILES=blkio.h                               \\
  151.                   bclose.c bexit.c  bflpop.c  bflpush.c  \\
  152.                   bflush.c bgetb.c  bgetbf.c  bgeth.c    \\
  153.                   bgethf.c bopen.c  bputb.c   bputbf.c   \\
  154.                   bputh.c  bputhf.c bsetbuf.c bsetvbuf.c \\
  155.                   bsync.c  lockb.c
  156.  
  157.           man:    $(MANFILES)
  158.                   cat $(MANFILES) | manx > $(MAN)
  159.  
  160.      The reference manual for this library is generated simply by
  161.      entering
  162.  
  163.           make man
  164.  
  165. ------------------------------------------------------------------------------*/
  166. #if __STDC__ == 1
  167. int main(int argc, char *argv[])
  168. #else
  169. int main(argc, argv)
  170. int argc;
  171. char *argv[];
  172. #endif
  173. {
  174.     int    lang        = LANG;        /* default language */
  175.     long    pagelen        = PAGELEN;    /* default page length */
  176.     int    page        = 0;        /* page number */
  177.     long    line        = 0;        /* line number */
  178.     int    i        = 0;        /* loop index */
  179.     char    s[MAXLINE + 1];            /* input line */
  180.     char *    endptr        = NULL;        /* pointer for strtol fct */
  181.  
  182.     /* process command line options and arguments */
  183.     /* language option */
  184.     if ((argc > 1) && (*argv[1] == '-')) {
  185.         argc--;
  186.         argv++;
  187.         lang = 0;
  188.         for (i = 0; i < sizeof(langs)/sizeof(*langs); i++) {
  189.             if (strcmp(*argv + 1, langs[i].option) == 0) {
  190.                 lang = i + 1;
  191.                 break;
  192.             }
  193.         }
  194.         if (lang == 0) {
  195.             printf("manx: invalid language option\n");
  196.             printf("%s\n", USAGE);
  197.             exit(EXIT_FAILURE);
  198.         }
  199.     }
  200.     /* page length argument */
  201.     if (argc > 1) {
  202.         argc--;
  203.         argv++;
  204.         errno = 0;
  205.         pagelen = strtol(*argv, &endptr, 10);
  206.         if (errno == ERANGE) {
  207.             printf("manx: page length argument out of range\n");
  208.             printf("%s\n", USAGE);
  209.             exit(EXIT_FAILURE);
  210.         }
  211.         if (endptr != NULL) {
  212.             if (endptr[0] != '\0') {
  213.                 printf("%s\n", USAGE);
  214.                 exit(EXIT_FAILURE);
  215.             }
  216.         }
  217.         if (pagelen < 0) {
  218.             printf("%s\n", USAGE);
  219.             exit(EXIT_FAILURE);
  220.         }
  221.     }
  222.     if (argc != 1) {
  223.         printf("%s\n", USAGE);
  224.         exit(EXIT_FAILURE);
  225.     }
  226.  
  227.     /* main loop */
  228.     while (1) {
  229.         /* read next line of input */
  230.         if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  231.             if (ferror(stdin) != 0) {
  232.                 fprintf(stderr, "*** Error reading standard input.  Exiting.\n");
  233.                 exit(EXIT_FAILURE);
  234.             }
  235.             break;
  236.         }
  237.         /* check for manual entry marker at beginning of line */
  238.         if (strncmp(s, langs[lang - 1].begin, strlen(langs[lang - 1].begin)) != 0) {
  239.             continue;
  240.         }
  241.         if (langs[lang - 1].flags & BLOCKCMT) {
  242.             if (strstr(s, langs[lang - 1].end) != NULL) {
  243.                 continue;
  244.             }
  245.         }
  246.         /* inner loop */
  247.         line = 0;
  248.         page = 1;
  249.         while (1) {
  250.             line++;
  251.             /* read next line of manual entry */
  252.             if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  253.                 if (ferror(stdin) != 0) {
  254.                     fprintf(stderr, "*** Error reading standard input.  Exiting.\n");
  255.                     exit(EXIT_FAILURE);
  256.                 }
  257.                 break;
  258.             }
  259.             /* check for end of entry marker */
  260.             if (langs[lang - 1].flags & LINECMT) {
  261.                 if (strncmp(s, langs[lang - 1].end, strlen(langs[lang - 1].end)) == 0) {
  262.                     break;
  263.                 }
  264.                 if (strncmp(s, langs[lang - 1].comment, strlen(langs[lang - 1].comment)) != 0) {
  265.                     break;
  266.                 }
  267.             } else {
  268.                 if (strstr(s, langs[lang - 1].end) != NULL) {
  269.                     break;
  270.                 }
  271.             }
  272.             if (s[strlen(s) - 1] != '\n') {
  273.                 fprintf(stderr, "*** Warning.  Maximum line length of %d exceeded.  Page %ld, line %ld.\n", (int)(sizeof(s) - 2), page, line);
  274.                 s[strlen(s) - 1] = '\n';
  275.             }
  276.             if (langs[lang - 1].flags & LINECMT) {
  277.                 if (manputs(s + strlen(langs[lang - 1].comment) , stdout) == -1) {
  278.                     fprintf(stderr, "*** Error writing line %ld, of page %ld.  Exiting\n", line, page);
  279.                     exit(EXIT_FAILURE);
  280.                 }
  281.             } else {
  282.                 if (manputs(s, stdout) == -1) {
  283.                     fprintf(stderr, "*** Error writing line %ld, of page %ld.  Exiting\n", line, page);
  284.                     exit(EXIT_FAILURE);
  285.                 }
  286.             }
  287.             if ((line >= pagelen) && (pagelen != 0)) {
  288.                 if (fputs(PAGINATOR, stdout) == EOF) {
  289.                     fprintf(stderr, "*** Error writing paginator to standard output.  Exiting.\n");
  290.                     exit(EXIT_FAILURE);
  291.                 }
  292.                 line = 0;
  293.                 page++;
  294.             }
  295.         }
  296.         /* write last paginator */
  297.         if ((line != 1) && (pagelen != 0)) {
  298.             if (fputs(PAGINATOR, stdout) == EOF) {
  299.                 fprintf(stderr, "*** Error writing paginator to standard output.  Exiting.\n");
  300.                 exit(EXIT_FAILURE);
  301.             }
  302.             page++;
  303.         }
  304.         /* check if end of file */
  305.         if (feof(stdin) != 0) {
  306.             break;
  307.         }
  308.     }
  309.  
  310.     exit(EXIT_SUCCESS);
  311. }
  312.  
  313. /*------------------------------------------------------------------------------
  314. DESCRIPTION
  315.      The manputs function writes the null-terminated string pointed to
  316.      by cs to the named output stream.  Any manx escape sequence found
  317.      in the string is converted to the character it represents before
  318.      being output.
  319.  
  320. DIAGNOSTICS
  321.      Upon successful completion, a value of 0 is returned.  Otherwise,
  322.      a value of -1 is returned.
  323.  
  324. ------------------------------------------------------------------------------*/
  325. #if __STDC__ == 1
  326. static int manputs(const char *cs, FILE *fp)
  327. #else
  328. static int manputs(cs, fp)
  329. char *cs;
  330. FILE *fp;
  331. #endif
  332. {
  333.     char t[MAXLINE + 1];    /* target string */
  334.     int i = 0;        /* index into target string */
  335.     char c = '\0';
  336.  
  337.     /* convert string to output format */
  338.     for (i = 0; *cs != '\0'; i++) {
  339.         if (i > sizeof(t)) {
  340.             return -1;
  341.         }
  342.         c = *cs++;
  343.         /* check for escape sequence */
  344.         if ((c == BACKSLASH) && (*cs != '\0')) {
  345.             c = *cs++;
  346.             switch (c) {
  347.             case 'a':    /* audible alert */
  348.                 c = '\a';
  349.                 break;    /* case 'a': */
  350.             case 'b':    /* backspace */
  351.                 c = '\b';
  352.                 break;    /* case 'b': */
  353.             case 'r':    /* carriage return */
  354.                 c = '\r';
  355.                 break;    /* case 'r': */
  356.             case 't':    /* horizontal tab */
  357.                 c = '\t';
  358.                 break;    /* case 't': */
  359.             case '\\':    /* backslash */
  360.                 c = '\\';
  361.                 break;    /* case '\\': */
  362.             default:    /* ignore backslash */
  363.                 break;    /* default: */
  364.             }
  365.         }
  366.         t[i] = c;
  367.     }
  368.     t[i] = '\0';
  369.  
  370.     /* write converted string to fp */
  371.     if (fputs(t, fp) == EOF) {
  372.         return -1;
  373.     }
  374.  
  375.     return 0;
  376. }
  377.  
  378. #if __STDC__ != 1
  379. char *strstr(cs, ct)
  380. char *cs;
  381. char *ct;
  382. {
  383.     int ctlen = 0;
  384.  
  385.     if ((cs == NULL) || (ct == NULL)) {
  386.         return NULL;
  387.     }
  388.  
  389.     ctlen = strlen(ct);
  390.     while (*cs != '\0') {
  391.         if (strncmp(cs, ct, ctlen) == 0) {
  392.             return cs;
  393.         }
  394.         cs++;
  395.     }
  396.  
  397.     return NULL;
  398. }
  399. #endif
  400.